#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h> /* for inet_addr */
#include "amever.h"
#include "client.h"

int network_serve(char *listen_ip, int port) {
	struct sockaddr_in server_address;
	int fd;
	int result;
	int yes = 1;

	if (inet_addr(listen_ip) == INADDR_NONE) { // not always -1
		perror("Invalid listen IP (socket.c: make_listen_port).");
		exit(-1);
	}

	fd = socket(AF_INET, SOCK_STREAM, 0);

	result = fcntl(fd, F_SETFL, O_NONBLOCK);
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof yes);
//    setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof yes);
	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof yes);

	server_address.sin_family        = AF_INET;
	server_address.sin_addr.s_addr   = inet_addr(listen_ip);
	server_address.sin_port = htons(port);
	
	amelog("Opening %s:%d for reading the clients.\n", listen_ip, port);
	
	result = bind(fd, (struct sockaddr*)&server_address, sizeof(server_address));
	if (result == -1) {
		amelog("bind error\n");
		exit(-1);
	}

	result = listen(fd, 5);
	if (result == -1) { // error
		amelog("listen error\n");
		exit(-1);
	}

	return fd;
}

int network_accept(int listen_fd) {
	int fd;
	struct sockaddr_in *client_address = malloc(sizeof(struct sockaddr_in));
	int len;
	int result;
	int yes = 1;
	
	len = sizeof(client_address);
	fd = accept(listen_fd, (struct sockaddr*)client_address, &len);
	
	int success = 0, i=0;
	for (i=0;i<MAX_BAN_LIST;i++)
	{
		if (client_address->sin_addr.s_addr == s.network_banList[i])
		{
			success = 1;
			break;
		}
	}
	
	if (!success)
	{
		amelog("Didn't accept client from %s\n", inet_ntoa(client_address->sin_addr));
		return 1;
	}
	
	if (fd < 0)
		return 0;
	
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof yes);
	setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof yes);
	
	result = fcntl(fd, F_SETFL, O_NONBLOCK);
	struct client *client;
	client = client_init(fd);
	client->s = client_address;
	return fd;
}

int network_shutdown (int fd) {
	shutdown(fd, O_RDWR);
	return 0;
}
